package com.rengwuxian.coursecoroutines._4_flow

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectIndexed
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlin.coroutines.EmptyCoroutineContext

/**
 * Flow的收集
 * Flow和协程切换、collect()、collectIndexed()、collectLatest()
 *
 * 1.flow{}中不允许切到别的协程发送数据。
 *   val flow = flow {
 *     /*launch(Dispatchers.IO) {
 *       delay(2000)
 *       emit(2)
 *     }*/
 *     delay(1000)
 *     emit(1)
 *   }
 *   flow的collect代码就相当于把上游数据搬下来，emit占位替换程处理代码。
 *   下游collect的代码是程序员预期设置的Dispatchers，如果flow中切了线程，会和调用者预期不一致，为了达成这种一致，协程才用了强制措施，不让flow的上游切协程。
 *  而Channel是数据生产和使用拆开的，使用还是在collect所在协程中。
 * 2.flow{}有个操作符flowOn(),可以用来切线程。
 * 3.还有一个操作符launchIn(scope)，也是一个便捷函数。通常和onEach{}一起使用。把flow的启动和处理放在一起了。
 *      flow.launchIn(scope) 等价于
 *      scope.launch {
 *          flow.collect{} // 空实现
 *      }
 *      // 等价写法：
 *      flow.onEach {
 *        println("flow: $it")
 *      }.launchIn(scope) // 在collect之前会操作一道，写法更简洁。
 *
 *      scope.launch(Dispatchers.Default) {
 *        flow.collect {
 *          println("flow: $it")
 *        }
 * 4.collectIndexed {} : 通过为回调函数提供index字段的形式为数据流标上序号。以0开始。
 * 5.collectLatest {} : 是mapLatest(action).buffer(0).collect()，是mapLatest和buffer的结合。
 */
fun main() = runBlocking<Unit> {
  val flow = flow {
    /*launch(Dispatchers.IO) {
      delay(2000)
      emit(2)
    }*/
    delay(1000)
    emit(1)
  }
  val scope = CoroutineScope(EmptyCoroutineContext)
  
  flow.onEach {
    println("flow: $it")
  }.launchIn(scope)
  
  scope.launch(Dispatchers.Default) {
    flow.collect {
      println("flow: $it")
    }
    flow.collectIndexed { index, value ->  }
    flow.collectLatest {  }
  }
  delay(10000)
}